package com.ky.tms.util;

import cn.hutool.core.io.resource.ResourceUtil;
import cn.hutool.core.util.HexUtil;

import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.security.KeyStore;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.Signature;
import java.security.cert.CertificateException;
import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate;
import java.util.*;

/**
 * 银联商务 私钥签名，公钥验签
 *
 * @author ZJ
 *
 */
public class SignUtil {
	private static String CHARSET_ENCODING = "UTF-8";
	private static String ALGORITHM = "SHA256withRSA";

	/**
	 * 排序参数获取签名字符串
	 * @param params
	 * @return
	 */
	private static String getSrcData(Map<String, Object> params) {
		SortedMap<String, Object> sortedMap = new TreeMap<>(params);

		StringBuilder toSign = new StringBuilder();
		for (String key : sortedMap.keySet()) {
			String value = params.get(key).toString();
			if (!"signature".equals(key) && !"key".equals(key)) {
				toSign.append(key).append("=").append(value).append("&");
			}
		}

		return toSign.toString().substring(0, toSign.toString().lastIndexOf("&"));
	}

	/**
	 * 签名
	 * @param params
	 * @return
	 */
	public static String sign(Map<String, Object> params) {

		String srcData = getSrcData(params);
		try {
			// 获取证书的私钥
			PrivateKey key = readPrivate();
			// 进行签名服务
			Signature signature = Signature.getInstance(ALGORITHM);
			signature.initSign(key);
			signature.update(srcData.getBytes(CHARSET_ENCODING));
			byte[] signedData = signature.sign();
//			return Base64.getEncoder().encodeToString(signedData);
			return HexUtil.encodeHexStr(signedData);
		} catch (Exception e) {
			e.printStackTrace();
		}
		return "";
	}

	/**
	 * 验签
	 *
	 * @param srcData
	 * @param signedData
	 * @return
	 */
	public static boolean verify(Map<String, Object> params, String signedData) {
		String srcData = getSrcData(params);
		if (srcData == null || signedData == null) {
			return false;
		}
		try {
			PublicKey publicKey = readPublic();
			Signature sign = Signature.getInstance(ALGORITHM);
			sign.initVerify(publicKey);
			sign.update(srcData.getBytes(CHARSET_ENCODING));
//			return sign.verify(Base64.getDecoder().decode(signedData));
			return sign.verify(HexUtil.decodeHex(signedData));
		} catch (Exception e) {
			e.printStackTrace();
		}
		return false;
	}

	/**
	 * 读取公钥
	 */
	private static PublicKey readPublic() {
		PublicKey pk = null;
		InputStream bais = null;
		try {
			CertificateFactory certificatefactory = CertificateFactory.getInstance("X.509");
			bais = ResourceUtil.getStream("cert" + File.separator + "rsa_public_prod.cer");
			X509Certificate cert = (X509Certificate) certificatefactory.generateCertificate(bais);
			pk = cert.getPublicKey();
		} catch (CertificateException e) {
			e.printStackTrace();
		} finally {
			if (bais != null) {
				try {
					bais.close();
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
		}
		return pk;
	}

	/**
	 * 读取私钥
	 *
	 * @param path
	 * @return
	 */
	private static PrivateKey readPrivate() {
		//私钥密码
		String privateKeyPwd = "123456";
//		Properties readPropertiesFile = readPropertiesFile();
//		String privateKeyPwd = Convert.toStr(readPropertiesFile.get("privateKeyPwd"));
//		if (privateKeyPwd == null) {
//			return null;
//		}
		InputStream stream = null;
		try {
			// 获取JKS 服务器私有证书的私钥，取得标准的JKS的 KeyStore实例
			KeyStore store = KeyStore.getInstance("pkcs12");
//            stream = new FileInputStream(new File(privateKeyPath));
			stream = ResourceUtil.getStream("cert" + File.separator + "rsa_private_prod.pfx");
			// jks文件密码，根据实际情况修改
			store.load(stream, privateKeyPwd.toCharArray());
			// 获取jks证书别名
			Enumeration en = store.aliases();
			String pName = null;
			while (en.hasMoreElements()) {
				String n = (String) en.nextElement();
				if (store.isKeyEntry(n)) {
					pName = n;
				}
			}
			// 获取证书的私钥
			PrivateKey key = (PrivateKey) store.getKey(pName, privateKeyPwd.toCharArray());
			return key;
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			if (stream != null) {
				try {
					stream.close();
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
		}
		return null;
	}

	/**
	 * 通过配置文件名读取内容
	 *
	 * @param fileName
	 * @return
	 */
	private static Properties readPropertiesFile() {
		Properties properties = new Properties();
		InputStream inputStream = ResourceUtil.getStream("application.properties");
		try {
			properties.load(new InputStreamReader(inputStream, "UTF-8"));
			return properties;
		} catch (Exception e) {
//            logger.info("————读取配置文件：" + fileName + "出现异常，读取失败————");
			e.printStackTrace();
		}
		return null;
	}

	public static void main(String[] args) {
//		String sign = sign("123", "E:\\工作\\云物流\\xlx_ylzf1.pfx", "xlx123456");
//		System.out.println(sign);

//		boolean verify = verify("123", sign, "E:\\工作\\云物流\\xlx_ylzf_gy1.cer");
//		System.out.println(verify);

//		Map<String, Object> map = new HashMap<String, Object>();
//		map.put("name", "张三");
//		map.put("s", "");
//
//		String sign = sign(map, "s");
//		System.out.println(sign);
//
//		boolean verify = verify(map, "s", sign);
//		System.out.println(verify);

		String sign = sign(null);
		System.out.println(sign);

	}
}
